home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Sample Code / AppsToGo / DTS.Lib / Print.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-24  |  10.7 KB  |  388 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:     DTS.Lib
  5. ** File:        print.c
  6. ** Written by:  Eric Soldan
  7. ** Based on:    Code from Pete "Luke" Alexander.
  8. **
  9. ** Copyright © 1989-1991 Apple Computer, Inc.
  10. ** All rights reserved.
  11. */
  12.  
  13. /* You may incorporate this sample code into your applications without
  14. ** restriction, though the sample code has been provided "AS IS" and the
  15. ** responsibility for its operation is 100% yours.  However, what you are
  16. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  17. ** after having made changes. If you're going to re-distribute the source,
  18. ** we require that you make it clear in the source that the code was
  19. ** descended from Apple Sample Code, but that you've made changes. */
  20.  
  21.  
  22.  
  23. /*****************************************************************************/
  24.  
  25.  
  26.  
  27. #include "DTS.Lib2.h"
  28. #include "DTS.Lib.protos.h"
  29.  
  30. #ifndef __ERRORS__
  31. #include <Errors.h>
  32. #endif
  33.  
  34. #ifndef __RESOURCES__
  35. #include <Resources.h>
  36. #endif
  37.  
  38. #ifndef __STRINGUTILS__
  39. #include "StringUtils.h"
  40. #endif
  41.  
  42.  
  43.  
  44. /*****************************************************************************/
  45.  
  46.  
  47.  
  48. static pascal void    PrintIdleProc(void);
  49. short                gPrintPage;
  50. static DialogPtr    gPrintingStatusDialog;
  51.  
  52.  
  53.  
  54. /*****************************************************************************/
  55.  
  56.  
  57.  
  58. /* This print-loop function is designed to be called under various situations.
  59. ** The big issue that it handles is finder printing.  If multiple documents
  60. ** are to be printed from the finder, the user should only see one job dialog
  61. ** for all the files.  (If a job dialog is shown for each file, how does the
  62. ** user know for which file the dialog is for?)  So, for situations where
  63. ** there is more than one file to be printed, call this code the first time
  64. ** with the firstJob boolean true.  Normally, the jobDlg boolean will also
  65. ** be true, except that under 7.0, you may be printing in the background.
  66. ** If this is the case, you don't want a job dialog for even the first file,
  67. ** and you should pass in false for the jobDlg boolean in this case.  For
  68. ** files 2-N, you should pass false for both booleans.  For regular application
  69. ** printing, you should pass true for both booleans, since the file is the
  70. ** first (only) file, and you are not in the background.
  71. **
  72. ** After calling this function to print a document, you need to call it
  73. ** again with a nil document handle.  The print record for the first (or only)
  74. ** document printed is preserved in a static variable.  This is so that the
  75. ** job dialog information can be passed on to documents 2-N in the print job.
  76. ** Calling this function with the document handle nil tells this function
  77. ** that you are done printing documents, and that the print record for the
  78. ** first job can be disposed of. */
  79.  
  80. #pragma segment Print
  81. OSErr    PrintDocument(FileRecHndl frHndl, Boolean jobDlg, Boolean firstJob)
  82. {
  83.     OSErr            err;
  84.     THPrint            prRecHndl;
  85.     TPPrPort        printPort;
  86.     GrafPtr            oldPort;
  87.     short            i, keepResFile, copies, fstPage, lstPage;
  88.     TPrStatus        status;
  89.     ControlHandle    proceedButton;
  90.     Rect             rct;
  91.     Handle            txtHndl;
  92.     Str255            txt, txt2;
  93.     PrIdleUPP        pidleupp;
  94.  
  95.     static THPrint    prMergeHndl;
  96.  
  97.     if (!frHndl) {
  98.         if (prMergeHndl) {
  99.             DisposeHandle((Handle)prMergeHndl);
  100.             prMergeHndl = nil;
  101.         }
  102.         return(noErr);
  103.     }
  104.  
  105.     gPrintingStatusDialog = nil;
  106.  
  107.     if (!(prRecHndl = (THPrint)NewHandle(sizeof(TPrint)))) return(memFullErr);
  108.         /* If we can't generate a print record handle, we are out of here. */
  109.  
  110.     BlockMove((Ptr)&((*frHndl)->d.doc.fhInfo.print), (Ptr)(*prRecHndl), sizeof(TPrint));
  111.         /* Get the document's print info into the print record handle. */
  112.  
  113.     GetPort(&oldPort);
  114.  
  115.     DoSetCursor(&qd.arrow);
  116.  
  117.     keepResFile = CurResFile();
  118.     PrOpen();
  119.     err = PrError();
  120.  
  121.     if (!err) {
  122.         if (!(*frHndl)->d.doc.fhInfo.printRecValid) {
  123.             PrintDefault(prRecHndl);            /* The document print record was never 
  124.             err = PrError();                    ** initialized.  Now is is. */
  125.         }
  126.         if (!err) {
  127.             PrValidate(prRecHndl);        /* Do this just 'cause Apple says so. */
  128.             err = PrError();
  129.         }
  130.         if (!err) {
  131.             if (jobDlg) {                /* User gets to click some buttons. */
  132.                 UnhiliteWindows();
  133.                 if (!(PrJobDialog(prRecHndl)))
  134.                     err = userCanceledErr;
  135.                 else
  136.                     err = PrError();
  137.                 HiliteWindows();
  138.             }
  139.         }
  140.         if (!err) {
  141.             if (!firstJob) {
  142.                 fstPage = (*prMergeHndl)->prJob.iFstPage;
  143.                 lstPage = (*prMergeHndl)->prJob.iLstPage;
  144.                 PrJobMerge(prMergeHndl, prRecHndl);
  145.                 (*prMergeHndl)->prJob.iFstPage = (*prRecHndl)->prJob.iFstPage = fstPage;
  146.                 (*prMergeHndl)->prJob.iLstPage = (*prRecHndl)->prJob.iLstPage = lstPage;
  147.                 err = PrError();
  148.                     /* For documents other than the first, do the PrJobMerge thing.
  149.                     ** Unfortunately, PrJobMerge is kind of broken.  The first and last
  150.                     ** page fields have to be cached and put back.  The rest of PrJobMerge
  151.                     ** seems to work okay. */
  152.             }
  153.         }
  154.  
  155.         if (!err) {            /* Put the defaulted/validated/jobDlg'ed print record in the doc. */
  156.             pidleupp = nil;
  157.             fstPage = (*prRecHndl)->prJob.iFstPage;
  158.             lstPage = (*prRecHndl)->prJob.iLstPage;
  159.             copies  = (*prRecHndl)->prJob.iCopies;
  160.             BlockMove((Ptr)(*prRecHndl), (Ptr)&((*frHndl)->d.doc.fhInfo.print), sizeof(TPrint));
  161.             (*frHndl)->d.doc.fhInfo.printRecValid = true;
  162.  
  163.             gPrintingStatusDialog = nil;
  164.             i = ((*prRecHndl)->prStl.wDev >> 8) & 0xFF;
  165.             if ((i == 1) || (i == 2))
  166.                 gPrintingStatusDialog = GetNewDialog(rPrStatusDlg, nil, (WindowPtr)-1);
  167.             if (gPrintingStatusDialog) {
  168.                     /* The ImageWriter driver uses ParamText, so we can’t.
  169.                     ** If we try to, then the printer name shows up, instead of
  170.                     ** the document name.  Due to this, we have to parse our
  171.                     ** own text.  We expect dialog item#4 to have a c/r in it.
  172.                     ** We use the c/r instead of ^0, due to the ImageWriter driver.
  173.                     ** We just replace the c/r with the name of the document. */
  174.                 GetDialogItem(gPrintingStatusDialog, 4, &i, (Handle *)&txtHndl, &rct);
  175.                 GetDialogItemText(txtHndl, txt);
  176.                 for (i = *txt; i; --i) {
  177.                     if (txt[i] == 13) {
  178.                         txt[i] = *txt - i;
  179.                         txt[0] = i - 1;
  180.                         break;
  181.                     }
  182.                 }        /* We now have two pascal strings -- one right after the other. */
  183.                 pcpy(txt2, txt);                                /* Copy the first string. */
  184.                 pcat(txt2, (*frHndl)->fileState.fss.name);        /* Append the document name. */
  185.                 pcat(txt2, txt + *txt + 1);                        /* Append the second string. */
  186.                 SetDialogItemText(txtHndl, txt2);
  187.                 GetDialogItem(gPrintingStatusDialog, 1, &i, (Handle *)&proceedButton, &rct);
  188.                 HiliteControl(proceedButton, 255);
  189.                     /* Setup the proceed/pause/cancel dialog with the document name. */
  190.                 pidleupp = NewPrIdleProc(PrintIdleProc);
  191.                 (*prRecHndl)->prJob.pIdleProc = pidleupp;
  192.                 UseResFile(keepResFile);        /* Hook in the proceed/pause/cancel dialog. */
  193.                 UnhiliteWindows();
  194.             }
  195.  
  196.             for (i = 1; (i <= copies) && (!err); ++i) {
  197.  
  198.                 printPort = PrOpenDoc(prRecHndl, nil, nil);
  199.                 if (!(err = PrError())) {
  200.  
  201.                     gPrintPage = 1;
  202.                     while (gPrintPage <= lstPage) {
  203.  
  204.                         PrOpenPage(printPort, nil);
  205.  
  206.                         if (!(err = PrError()))
  207.                             err = DoImageDocument(frHndl);
  208.                                 /* Do the print thing here. */
  209.  
  210.                         PrClosePage(printPort);
  211.  
  212.                         if (!gPrintPage) break;
  213.                         ++gPrintPage;
  214.                     }
  215.                     gPrintPage = 0;
  216.                 }
  217.                 PrCloseDoc(printPort);
  218.             }
  219.             if (pidleupp) DisposeRoutineDescriptor(pidleupp);
  220.         }
  221.  
  222.         if (
  223.             (!err) &&
  224.             ((*prRecHndl)->prJob.bJDocLoop == bSpoolLoop) &&
  225.             (!(err = PrError()))
  226.         ) {
  227.             PrPicFile(prRecHndl, nil, nil, nil, &status);
  228.             err = PrError();
  229.         }
  230.     }
  231.  
  232.     if (firstJob)
  233.         prMergeHndl = prRecHndl;
  234.     else
  235.         DisposeHandle((Handle)prRecHndl);
  236.  
  237.     if (gPrintingStatusDialog)
  238.         DisposeDialog(gPrintingStatusDialog);
  239.  
  240.     PrClose();
  241.     UseResFile(keepResFile);
  242.  
  243.     SetPort(oldPort);
  244.     HiliteWindows();
  245.  
  246.     if (err == iIOAbortErr)
  247.         err = noErr;
  248.  
  249.     return(err);
  250. }
  251.  
  252.  
  253.  
  254. /*****************************************************************************/
  255.  
  256.  
  257.  
  258. /* DonePrinting makes sure that PrintDocument gets rid of the prMergeHndl
  259. ** print record that is used for multiple document printing.  Call this after
  260. ** or the last document is printed, or you get a memory leak. */
  261.  
  262. #pragma segment Print
  263. void    DonePrinting(void)
  264. {
  265.     PrintDocument(nil, false, false);
  266. }
  267.  
  268.  
  269.  
  270. /*****************************************************************************/
  271.  
  272.  
  273.  
  274. /* PrintIdleProc will handle events in the 'Printing Status Dialog' which
  275. ** gives the user the option to 'Proceed', 'Pause', or 'Cancel' the current
  276. ** printing job during print time.
  277. **
  278. ** The buttons:
  279. **        1: Proceed
  280. **        2: Pause
  281. **        3: Cancel
  282. */
  283.  
  284. #pragma segment Print
  285. pascal void    PrintIdleProc(void)
  286. {
  287.     Boolean                button, paused;
  288.     ControlHandle        pauseButton, proceedButton;
  289.     DialogPtr            aDialog;
  290.     EventRecord            anEvent;
  291.     GrafPtr                oldPort;
  292.     Rect                 rct;
  293.     short                item, itemType, keepResFile;
  294.  
  295.     GetPort(&oldPort);
  296.  
  297.     UseResFile(keepResFile = CurResFile());
  298.  
  299.     GetDialogItem(gPrintingStatusDialog, 1, &itemType, (Handle *)&proceedButton, &rct);
  300.     HiliteControl(proceedButton, 255);
  301.     GetDialogItem(gPrintingStatusDialog, 2, &itemType, (Handle *)&pauseButton, &rct);
  302.  
  303.     paused = false;
  304.     do {
  305.         if (GetNextEvent((mDownMask + mUpMask + updateMask), &anEvent)) {
  306.             if (gPrintingStatusDialog != FrontWindow())
  307.                 SelectWindow(gPrintingStatusDialog);
  308.  
  309.             if (IsDialogEvent(&anEvent)) {
  310.                 button = DialogSelect(&anEvent, &aDialog, &item);
  311.  
  312.                 if ((button) && (aDialog == gPrintingStatusDialog)) {
  313.                     switch (item) {
  314.                         case 1:
  315.                             HiliteControl(pauseButton, 0);        /* Enable PAUSE    */
  316.                             HiliteControl(proceedButton, 255);    /* Disable PROCEED */
  317.                             paused = false;
  318.                             break;
  319.                         case 2:
  320.                             HiliteControl(pauseButton, 255);    /* Disable PAUSE  */
  321.                             HiliteControl(proceedButton, 0);    /* Enable PROCEED */
  322.                             paused = true;
  323.                             break;
  324.                         case 3:
  325.                             PrSetError(iPrAbort);               /* CANCEL printing */
  326.                             paused = false;
  327.                             break;
  328.                     }
  329.                 }
  330.             }
  331.         }
  332.     } while (paused != false); 
  333.  
  334.     SetPort(oldPort);
  335. }
  336.  
  337.  
  338.  
  339. /*****************************************************************************/
  340.  
  341.  
  342.  
  343. /* Call this from the application to present a style dialog.  The changes are
  344. ** automatically saved in the document. */
  345.  
  346. #pragma segment Print
  347. OSErr    PresentStyleDialog(FileRecHndl frHndl)
  348. {
  349.     OSErr        err;
  350.     THPrint        prRecHndl;
  351.     short        oldRes;
  352.  
  353.     if (!(prRecHndl = (THPrint)NewHandle(sizeof(TPrint)))) return(memFullErr);
  354.  
  355.     oldRes = CurResFile();
  356.     PrOpen();
  357.  
  358.     if (!(err = PrError())) {
  359.  
  360.         BlockMove((Ptr)&(*frHndl)->d.doc.fhInfo.print, (Ptr)*prRecHndl, sizeof(TPrint));
  361.             /* Get data, valid or not. */
  362.  
  363.         if (!(*frHndl)->d.doc.fhInfo.printRecValid)
  364.             PrintDefault(prRecHndl);
  365.         else
  366.             PrValidate(prRecHndl);
  367.  
  368.         if (!(err = PrError())) {
  369.             UnhiliteWindows();
  370.             if (PrStlDialog(prRecHndl)) {
  371.                 BlockMove((Ptr)*prRecHndl, (Ptr)&(*frHndl)->d.doc.fhInfo.print, sizeof(TPrint));
  372.                 (*frHndl)->d.doc.fhInfo.printRecValid = true;
  373.             }
  374.             else err = userCanceledErr;
  375.             HiliteWindows();
  376.         }
  377.     }
  378.  
  379.     DisposeHandle((Handle)prRecHndl);
  380.     PrClose();
  381.     UseResFile(oldRes);
  382.  
  383.     return(err);
  384. }
  385.  
  386.  
  387.  
  388.